#pragma once

#if defined(__linux__)

#include "IOMultiplexer.h"

#include <memory>
#include <unistd.h>
#include <sys/epoll.h>

namespace network {

    class Epoll : public IOMultiplexer {

    public:

        /**
          * @brief  创建一个epoll模型
          * @param  max_size 设置为每次wait返回的最大数量 默认为128
          */
        explicit Epoll(int max_size = 128);

        ~Epoll() override {
            close(epoll_fd_);
        };

        /**
          * @brief  获取第index个事件的引用
          * @note   如果index超出最大epoll_event数组长度，会抛出std::out_of_range异常
          * @param  index 索引
          * @retval 对应的epoll_event结构体的引用
          */
        struct epoll_event &operator[](int index);

        /**
          * @brief  设置epoll关注指定文件描述符的指定IO事件
          * @param  fd 要加入检测的文件描述符
          * @param  event_type 关注的IO事件
          * @retval 是否成功将事件添加到epoll模型上
          */
        bool add(int fd, EventType event_type) override;

        /**
          * @brief  修改epoll关注的事件类型
          * @note   None
          * @param  fd    要修改的文件描述符
          * @param  event 要关注的类型
          * @retval 是否修改成功
          */
        bool mod(int fd, EventType event) override;

        /**
          * @brief  将Epoll对象上指定的fd对应的epoll_event删除
          * @note   该函数在删除指定的fd后不会自动关闭该fd，请手动关闭
          * @param  要删除的fd
          * @retval 是否成功删除
          */
        bool del(int fd) override;

        /**
          * @brief  等待epoll文件描述符上的I/O事件
          * @note   epoll_wait返回小于0时会抛出runtime_error异常
          * @param  reactor 反应堆指针
          * @retval 就绪事件个数
          */
        int dispatch(Reactor *reactor) override;

    private:

        // epoll文件描述符
        int epoll_fd_;

        // epoll_event事件集合
        std::shared_ptr<struct epoll_event> events_;

        // epoll缓存事件
        struct epoll_event event_{};

        // 每次wait返回的epoll_event最大舒利昂
        int max_size_;

    };

}

#endif